﻿// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Mappers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Linq;
using Serilog;
using Autofac;
using ZFY.Core;
using Microsoft.Extensions.FileProviders;
using System.IO;
using ZFY.AspNetCore;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using ZFY.UMC.API.Model;

namespace ZFY.UMC.Identity
{
    public class Startup
    {

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }

        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            // uncomment, if you want to add an MVC-based UI
            services
                .AddControllersWithViews(x =>
                {
                    x.Filters.Add(typeof(ZFYResultFilter));
                    //x.Filters.Add(typeof(ExceptionsFilter));
                })
                .AddNewtonsoftJson(options =>
                {
                    //忽略循环引用
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                    //设置时间格式
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                    options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
                })
                .AddRazorRuntimeCompilation()
                .AddControllersAsServices();
            services.AddSameSiteCookiePolicy();
            services.AddCors(x => x.AddPolicy("cors", policy => policy.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin()));
            
            string connectionString = Configuration.GetConnectionString("SqlLite");
            var migrationsAssembly = "ZFY.UMC.API.Model";
            ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder =>
            {
                builder
                    .AddFilter((category, level) =>
                        category == DbLoggerCategory.Database.Command.Name
                        && level == LogLevel.Information)
                    .AddConsole();
            });


            services.AddScoped<CurrentUserProfile>();

            services.AddDbContext<ZFYIdentityDbContext>(options => options.UseSqlite(connectionString,sql=>sql.MigrationsAssembly(migrationsAssembly)).UseLoggerFactory(MyLoggerFactory));

            //services.ConfigureApplicationCookie(x =>
            //{
               
            //    x.ExpireTimeSpan = new TimeSpan(0,1,0);
             
              
            //});

            services.Configure<IdentityOptions>(options =>
            {
               
                // Default Password settings.
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 6;
                options.Password.RequiredUniqueChars = 0;
                options.Lockout.AllowedForNewUsers = false;
                options.ClaimsIdentity.UserNameClaimType = ZFYProfileClaimTypes.Name;
                options.ClaimsIdentity.RoleClaimType = ZFYProfileClaimTypes.Role;
                options.ClaimsIdentity.UserIdClaimType = ZFYProfileClaimTypes.UserId;
                options.ClaimsIdentity.EmailClaimType = ZFYProfileClaimTypes.Email;
               
                
            });
            
            services.AddIdentity<User, Role>()
                .AddRoles<Role>()
                .AddEntityFrameworkStores<ZFYIdentityDbContext>()
                .AddDefaultTokenProviders()
                .AddErrorDescriber<ZFYIdentityErrorDescriber>()
                .AddClaimsPrincipalFactory<ZFYUserClaimsPrincipalFactory>();

            

            var builder = services.AddIdentityServer(options =>
            { 
            //{
                //options.Authentication.CookieAuthenticationScheme = "umc";
               
                //options.Authentication.CookieLifetime = TimeSpan.FromSeconds(5);
                //options.Authentication.CookieSlidingExpiration = false;
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.Csp.Level = IdentityServer4.Models.CspLevel.One;
                options.Csp.AddDeprecatedHeader = false;
                // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
                options.EmitStaticAudienceClaim = true;
                options.InputLengthRestrictions = new IdentityServer4.Configuration.InputLengthRestrictions() { RedirectUri = 10000 };
               
            
            })
                .AddAspNetIdentity<User>()
                // this adds the config data from DB (clients, resources)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b =>
                        b.UseSqlite(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b =>
                        b.UseSqlite(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    // options.TokenCleanupInterval = 15; // frequency in seconds to cleanup stale grants. 15 is useful during debugging
                })
                .AddProfileService<ZFYProfileService>();
            // not recommended for production - you need to store your key material somewhere secure
            builder.AddDeveloperSigningCredential();
            
            //services.AddSwaggerGen(x => x.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "IdentityServerApi", Version = "v1" }));
            //services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
            services.AddHttpContextAccessor();
            //services.AddAuthentication(x => {

            //    x.DefaultScheme = "umc";
            //    x.DefaultAuthenticateScheme = "umc";
            //    x.DefaultChallengeScheme = "umc";
            //    x.DefaultForbidScheme = "umc";
            //    x.DefaultForbidScheme = "umc";
            //    x.DefaultSignInScheme = "umc";
            //    x.DefaultSignOutScheme = "umc";
            //})
            //   .AddCookie("umc", x => {
            //       x.SlidingExpiration = true;
            //       x.ExpireTimeSpan = TimeSpan.FromHours(5);
            //   });
            //services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));
            services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));
        }

        public void Configure(IApplicationBuilder app)
        {
            InitializeDatabase(app);
            app.UseCors("cors");
            app.UseCookiePolicy();
            app.UseSerilogRequestLogging();
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //StaticInfo.ServiceProvider = app.ApplicationServices;
            //app.UseSwagger();

            //app.UseSwaggerUI(c =>
            //{
            //    c.SwaggerEndpoint("/swagger/v1/swagger.json", "IdentityServerApi");
            //    // 将swagger首页，设置成我们自定义的页面，记得这个字符串的写法：解决方案名.index.html
            //    c.RoutePrefix = "swagger"; //路径配置，设置为空，表示直接在根域名（localhost:8001）访问该文件,注意localhost:8001/swagger是访问不到的，去launchSettings.json把launchUrl去掉，如果你想换一个路径，直接写名字即可，比如直接写c.RoutePrefix = "doc";
            //});
            //app.UseHttpsRedirection();
            // uncomment if you want to add MVC
            app.UseFileServer(enableDirectoryBrowsing: false);

            app.UseRouting();

            app.Use(async (x, y) => { 
                await y(); 
            
            });

            app.UseIdentityServer();

            // uncomment, if you want to add MVC
            app.UseAuthorization();

            app.Use(async (x, y) => {
                await y();

            });
            app.UseFileServer(new FileServerOptions
            {
                FileProvider = new PhysicalFileProvider(
            Path.Combine(Environment.ContentRootPath, "Uploads")),
                RequestPath = "/Uploads",
                EnableDirectoryBrowsing = true
            });
            app.UseZFY();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
        private void InitializeDatabase(IApplicationBuilder app)
        {
            using (var serviceScope = app.ApplicationServices.CreateScope())
            {
                serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
                
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                var identityContext = serviceScope.ServiceProvider.GetRequiredService<ZFYIdentityDbContext>();
                context.Database.Migrate();
                identityContext.Database.Migrate();

                if (!identityContext.Users.Any())
                {
                    var userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<User>>();
                    identityContext.Roles.Add(Config.Role);
                    userManager.CreateAsync(Config.User);
                    identityContext.SaveChanges();
                }
                if (!context.Clients.Any())
                {
                    
                    foreach (var client in Config.Clients)
                    {
                        context.Clients.Add(client.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.IdentityResources.Any())
                {
                    foreach (var resource in Config.IdentityResources)
                    {
                        context.IdentityResources.Add(resource.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.ApiResources.Any())
                {
                    foreach (var resource in Config.ApiResource)
                    {
                       
                        context.ApiResources.Add(resource.ToEntity());
                    }
                    foreach (var apiScope in Config.ApiScopes)
                    {
                        context.ApiScopes.Add(apiScope.ToEntity());
                    }
                    context.SaveChanges();
                }
            }
        }
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            //containerBuilder.RegisterModule<AutofacModule>();
        }
    }
}
